"""
pip install python-consul2 loguru
"""
import time
import consul
from loguru import logger
from typing import Optional, Dict, Any, List


class ConsulClient:
    """
    Consul客户端封装类，提供服务注册、发现、健康检查等功能
    """
    def __init__(self, host: str = '127.0.0.1', port: int = 8500, token: Optional[str] = None):
        """
        初始化Consul客户端
        
        Args:
            host: Consul服务器地址
            port: Consul服务器端口
            token: 访问令牌（如果启用了ACL）
        """
        self.consul_client = consul.Consul(host=host, port=port, token=token)
        logger.info(f"连接到Consul Server: {host}:{port}")
    
    @staticmethod
    def create_http_check(http_url: str, interval: str = '10s', timeout: str = '5s') -> Dict[str, Any]:
        """
        创建HTTP健康检查配置
        文档: https://developer.hashicorp.com/consul/docs/register/health-check/vm#http-check-configuration
        
        Args:
            http_url: 健康检查URL
            interval: 检查间隔（默认10秒）
            timeout: 检查超时时间（默认5秒）
        
        Returns:
            Dict[str, Any]: 健康检查配置字典
        """
        return {
            'method': 'HEAD',
            'http': http_url,
            'interval': interval,
            'timeout': timeout,
        }

    def register_service(
        self, name: str, address: str, port: int, 
        service_id: Optional[str] = None, 
        tags: Optional[List[str]] = None, 
        check: Optional[Dict[str, Any]] = None
    ) -> bool:
        """
        注册服务到Consul
        
        Args:
            name: 服务名称
            address: 服务地址
            port: 服务端口
            service_id: 服务ID（可选，默认为None）
            tags: 服务标签列表
            check: 健康检查配置
        
        Returns:
            bool: 注册是否成功
        """
        try:
            # 注册配置
            registration = {
                'name': name,
                'address': address,
                'port': port,
                'service_id': service_id,
                'tags': tags,
                'check': check
            }
            # 注册
            result: bool = self.consul_client.agent.service.register(**registration)
            logger.info(f"服务注册{'成功' if result else '失败'}: {name} >>> {service_id}")
            return result
        except Exception as e:
            logger.error(f"服务注册异常: {e}")
            return False
    
    def deregister_service(self, service_id: str) -> bool:
        """
        从Consul注销服务
        
        Args:
            service_id: 服务ID
            
        Returns:
            bool: 注销是否成功
        """
        try:
            result: bool = self.consul_client.agent.service.deregister(service_id)
            logger.info(f"服务注销{'成功' if result else '失败'}: {service_id}")
            return result
        except Exception as e:
            logger.error(f"服务注销异常: {e}")
            return False
    
    def service_names(self) -> List[str]:
        """
        获取所有已注册的服务名称
        
        Returns:
            list: 服务名称列表
        """
        try:
            services = self.consul_client.agent.services()
            logger.info(f"总共注册了 {len(services)} 个服务")
            return list(services.keys())
        except Exception as e:
            logger.error(f"列出服务异常: {e}")
            return []

    def get_health_services(self, service_name: str) -> List[Dict[str, Any]]:
        """
        获取指定服务的健康实例
        
        Args:
            service_name: 服务名称
            
        Returns:
            list: 健康服务实例列表
        """
        health_services = []
        try:
            _, services = self.consul_client.health.service(service_name, passing=True)
            for service in services:
                service_info = {
                    'id': service['Service']['ID'],
                    'name': service['Service']['Service'],
                    'address': service['Service']['Address'],
                    'port': service['Service']['Port'],
                    'tags': service['Service'].get('Tags', [])
                }
                health_services.append(service_info)
            
            logger.info(f"找到 {len(health_services)} 个健康的 {service_name} 服务实例")
        except Exception as e:
            logger.error(f"获取服务异常: {e}")

        return health_services
    
    def set_key_value(self, key: str, value: str) -> bool:
        """
        在Consul KV存储中设置键值对
        
        Args:
            key: 键名
            value: 键值
            
        Returns:
            bool: 设置是否成功
        """
        try:
            result: bool = self.consul_client.kv.put(key, value)
            logger.info(f"设置键值对{'成功' if result else '失败'}: {key}")
            return result
        except Exception as e:
            logger.error(f"设置键值对异常: {e}")
            return False
    
    def get_key_value(self, key: str) -> Optional[str]:
        """
        从Consul KV存储中获取键值对
        
        Args:
            key: 键名
            
        Returns:
            str or None: 获取的值，如果不存在则返回None
        """
        try:
            _, data = self.consul_client.kv.get(key)
            if data:
                value = data['Value'].decode('utf-8') if data['Value'] else ''
                logger.info(f"获取键值对成功: {key} = {value}")
                return value
            else:
                logger.warning(f"键不存在: {key}")
                return
        except Exception as e:
            logger.error(f"获取键值对异常: {e}")
            return


# 使用示例
def main():
    """
    主函数，展示Consul Python库的基本用法
    """
    print("Consul Python库使用示例")
    print("=" * 50)
    
    # 创建Consul客户端
    consul_client = ConsulClient()
    
    # 示例1: 列出所有服务
    print("\n1. 列出所有已注册的服务:")
    print(consul_client.service_names())
    
    # 示例2: 设置和获取KV值
    print("\n2. 键值存储操作:")
    consul_client.set_key_value('config/key', 'value')
    consul_client.get_key_value('config/key')
    
    # 示例3: 注册服务（带HTTP健康检查）
    print("\n3. 注册服务:")
    # 注意: 这里的健康检查URL需要是实际可访问的，否则服务会被标记为不健康
    # 以下是一个示例，实际使用时需要替换为真实的健康检查端点
    def aaa(server_name: str, i: int):
        health_check = consul_client.create_http_check(
            http_url=f"http://192.168.0.109:100{i}/health",
            interval="10s",
            timeout="5s"
        )
        # 注册一个测试服务
        consul_client.register_service(
            name=server_name,
            address="192.168.0.109",
            port=1000 + i,
            service_id=f'{server_name}-{i}',
            tags=["python", "health-api"],
            check=health_check
        )
    server_name = 'api-service'
    for i in range(1, 4):
        aaa(server_name, i)
    
    # 再次列出服务，验证注册是否成功
    print("\n4. 再次列出所有服务:")
    time.sleep(2)
    print(consul_client.service_names())
    
    # 示例4: 获取服务实例
    print("\n5. 获取服务实例:")
    time.sleep(2)
    services = consul_client.get_health_services(server_name)
    for service in services:
        print(service)
    
    # 示例5: 注销服务（演示用，实际使用时可能不需要立即注销）
    # 取消下面的注释可以测试服务注销
    # time.sleep(5)  # 等待几秒钟
    # consul_client.deregister_service(service_id)
    
    print("\n" + "=" * 50)
    print("Consul Python库使用示例完成")


if __name__ == "__main__":
    main()
